<!DOCTYPE html>
<html>
    <head lang="en">
        <script type="text/javascript" src="http://localhost:9000/public/js/lib/d3.min.js" ></script>
        <title>柱状图</title>
        <style>
            .z-zhu-svg{

            }
            .z-zhu-zhu{

            }
            .z-zhu-color-1{
                fill:rgb(124, 181, 236);
                stroke:rgb(124, 181, 236);
            }
            .z-zhu-color-2{
                fill:rgb(67, 67, 72);
                stroke:rgb(67, 67, 72);
            }
            .z-zhu-color-3{
                fill:rgb(144, 237, 125);
                stroke:rgb(144, 237, 125);
            }
            .z-zhu-color-4{
                fill:rgb(247, 163, 92);
                stroke:rgb(247, 163, 92);
            }
            .z-axis path ,.z-axis line {
                fill:none;
                stroke:#000;
                shape-rendering: crispEdges;
            }
            .z-axis-x .tick text{
                font-size:13px;
            }
            .z-axis-y .tick text{
                display:none;
            }
            .z-axis-text{
                text-anchor:middle;
            }
            .z-zhu-wrap{

            }
            .z-zhu-line{
                stroke:#000;
                opacity:.15;
                fill:none;
            }
            .z-zhu-intro-g{
                cursor:pointer;
            }
            .z-zhu-intro-g:hover rect{
                transform:scale(2,2);
            }
            .z-zhu-intro-g rect{
                transition:all .3s ease-in-out 0s;
                transform:scale(1,1) ;
                transform-origin: 100% 50%;
            }
            .z-zhu-intro-g-disable rect{
                fill:#aaa;
                stroke:#aaa;
            }
            .z-zhu-intro-g-disable text{
                fill:#aaa;
            }
            .z-zhu-intro-g-disable:hover rect{
                transform:scale(1,1);
            }
            .z-zhu-g-txt{
                font-size:13px;
            }
            .z-zhu-g-wrap{
                display:none;
            }
            .z-hide{
                display:none;
            }
            .z-show{
                display:block;
            }
            .z-zhu-g-text-path{
                fill:none;
                stroke-width:2px;
            }
        </style>
    </head>
    <body>
        <svg class="z-zhu-svg">

        </svg>
        <script type="text/javascript" >
            (function(win){
                var width = 1135 ;
                var height = 485 ;
                var margin = {
                    left : 100 ,
                    right : 100 ,
                    top : 20 ,
                    bottom : 100
                } ;
                var getDayReg = /^\d{4}\d{2}(\d{2})$/ ;
                var getMonthReg = /^\d{4}(\d{2})(\d{2})$/ ;
                var data = [
                    {"bizDate":"20150508","pv":236792,"uv":152144,"clickPv":167203,"clickUv":52868},
                    {"bizDate":"20150507","pv":227673,"uv":140201,"clickPv":149503,"clickUv":48341},
                    {"bizDate":"20150506","pv":241228,"uv":153624,"clickPv":139204,"clickUv":50808},
                    {"bizDate":"20150505","pv":232439,"uv":148559,"clickPv":135650,"clickUv":50922},
                    {"bizDate":"20150504","pv":256871,"uv":166696,"clickPv":145030,"clickUv":54523},
                    {"bizDate":"20150503","pv":173049,"uv":119987,"clickPv":72818,"clickUv":30518},
                    {"bizDate":"20150502","pv":164954,"uv":114298,"clickPv":65632,"clickUv":25983}
                ].sort(function(a,b){
                            var aDay = a.bizDate.replace(getDayReg,function(s,$1){ return parseInt($1)||0; }) ;
                            var bDay = b.bizDate.replace(getDayReg,function(s,$1){ return parseInt($1)||0; }) ;
                            return aDay > bDay ;
                        }) ;
                //@note 月份转化
                var monthRange = ['January','February','March','April','May','June','July','August','September','October','November','December'] ;
                var month = d3.scale.ordinal()
                        .domain(d3.range(12).map(function(i){return i+1;}))
                        .range(monthRange);
                var outWrap = d3.select('svg.z-zhu-svg') ;
                var svg = outWrap.attr({
                    'width' : width ,
                    'height' : height
                }).append('g').attr({
                    'class' : 'z-zhu-wrap'
                })  ;
                var yTicks = 5 , i = 0 , j = 0  ;
                var y = d3.scale.linear()
                        .domain([0,d3.max( data , function(d){
                            var digit = Math.pow(10,(d.pv+'').length - 1) ;
                            var count = Math.ceil(d.pv/digit) ;
                            return digit*count;
                        })]).range([height-margin.bottom,margin.top]) ;
                var x = d3.scale.linear()
                        .domain([0,data.length])
                        .range([margin.left,width-margin.right]);

                //@note 添加网格
                var line = d3.svg.line().x(function(d){return d[0];}).y(function(d){return d[1];}) ;
                var xDomain = x.domain() ;
                var yDomain = y.domain() ;
                for( i = 0 ; i <= xDomain[1] ; i++){
                    svg.append('path').attr({
                        'class' : 'z-zhu-line' ,
                        'd' : line(d3.transpose([[x(i),x(i)],y.range()]))
                    }) ;
                }
                for( i = 0 ; i <= yTicks + 1 ; i++ ){
                    var flag = y.domain()[1] / ( yTicks + 1 ) * i ;
                    svg.append('path').attr({
                        'class' : 'z-zhu-line' ,
                        d : line( d3.transpose([ x.range() , [ y(flag) , y(flag) ]  ]) )
                    }) ;
                }

                //@note x、y坐标轴
                var yAxis = d3.svg.axis().scale(y).orient('left').ticks(yTicks) ;
                var xAxis = d3.svg.axis().scale(x).orient('bottom').ticks(data.length) ;

                //@note 添加坐标轴
                var yg = svg.append('g').attr({
                    'class' : 'z-axis z-axis-x' ,
                    'transform' : 'translate(' + margin.left + ',0)'
                }).call(yAxis) ;
                var xg = svg.append('g').attr({
                    'class' : 'z-axis z-axis-y' ,
                    'transform' : 'translate(0,' + ( height - margin.bottom ) + ')'
                }).call(xAxis) ;

                //@note 添加x坐标文本
                var xText = svg.selectAll('text.z-axis-text').data(data).enter().append('text').attr({
                    class : 'z-axis-text' ,
                    x : function(d,i){
                        return x(i) ;
                    } ,
                    transform : 'translate(' +  ( x(1) - x(0) ) / 2 + ',20)' ,
                    cy : function(){ return 30 ; } ,
                    y : height - margin.bottom
                }).text(function(d){
                    return d.bizDate.replace(getMonthReg,function(s,$1,$2){ return month(parseInt($1)) + ' ' + $2 ; }) ;
                }) ;

                var zhuStyle = [
                    { name : 'pv' , 'cls' : 'z-zhu-color-1', show : true },
                    { name : 'uv' , 'cls' : 'z-zhu-color-2' , show : true },
                    { name : 'clickPv' , 'cls' : 'z-zhu-color-3' , zh : 'pv点击' , show : true },
                    { name : 'clickUv' , 'cls' : 'z-zhu-color-4' , zh : 'uv点击' , show : true }
                ] ;
                //@note 柱状图
                var zhuGap = 15, zhuMargin = 10 ;
                var zhuCalcu = function( ele , d ){
                    var self = ele , totalWidth = x(1) - x(0)  ;
                    var len = d3.sum(zhuStyle,function(d){ if(d.show){return 1;}else{return 0;} }) ;
                    var zWidth = ( totalWidth - zhuMargin * ( len - 1 ) - zhuGap * 2 ) / len ;

                    //@note 遮罩层 用于触发mouseover
                    ele.append('rect').attr({
                        width : totalWidth ,
                        height : y(0) ,
                        y : -y(0) ,
                        opacity:0
                    }) ;
                    for( var i = 0 ; i < zhuStyle.length ; i++ ){
                        var one = zhuStyle[i] ;
                        var rect = self.append( 'rect' ).attr({
                            'class' : one.cls
                        }) ;
                        var zHeight = y.range()[0] - y(d[one.name]);
                        rect.attr({
                            'width' : zWidth ,
                            'height' :  zHeight ,
                            'x' : zhuGap + i * ( zWidth + zhuMargin ) ,
                            'y' : -zHeight
                        }) ;
                    } ;
                } ;
                var zhuAddText = function(self,d){
                    var g = self.append('g').attr({
                        'class' : 'z-zhu-g-wrap' ,
                        'transform' : 'translate(100,-' + ( y(y.domain()[0]) - 100 )  + ')'
                    }) ;
                    var len = zhuStyle.length ;
                    for( var i = 0 ; i < len ; i++ ){
                        var one = zhuStyle[i] ;
                        var gr = g.append('g').attr({
                            'class' : 'z-zhu-g-txt ' + 'z' + one.cls
                        }) ;
                        gr.append('rect').attr({
                            'class' : one.cls ,
                            width : 130 ,
                            height : 20 ,
                            y : ( len - i ) * -30 ,
                            x : -5
                        }).style({
                            'fill':'#fff'
                        }) ;
                        gr.append('text').attr({
                            'x' : 0 ,
                            'y' : ( len - i ) * -30 + 15
                        }).text( ( one.zh || one.name ) + ' : ' + d[one.name] ) ;
                        g.append('path').attr({
                            class : one.cls + ' z-zhu-g-text-path'
                        }) ;
                    }
                } ;
                var g = svg.selectAll('g.z-zhu-chart').data(data).enter().append('g').attr({
                    class : 'z-zhu-chart' ,
                    transform : function(d,i){
                        return 'translate(' + x(i) + ',' + ( height - margin.bottom ) + ')' ;
                    }
                }).each(function(d){
                    var self = d3.select(this) ;

                    //@note 计算柱状图 并绘制
                    zhuCalcu( self , d ) ;

                    //@note 文字说明
                    zhuAddText( self , d ) ;

                }).sort(function(a,b){
                    var aDay = a.bizDate.replace(getDayReg,function(s,$1){ return parseInt($1)||0; }) ;
                    var bDay = b.bizDate.replace(getDayReg,function(s,$1){ return parseInt($1)||0; }) ;
                    return aDay < bDay ;
                }) ;

                var oneChart = d3.selectAll('.z-zhu-chart') ;
                oneChart.on('mouseover',function(){

                    var self = d3.select(this) ;
                    self.select('.z-zhu-g-wrap').style('display','block');

                }).on('mouseout',function(){

                    var self = d3.select(this) ;
                    self.select('.z-zhu-g-wrap').style('display','none');


                }) ;
                var pointLine = d3.svg.line().x(function(d){ return d[0]; }).y(function(d){return d[1];}) ;
                oneChart.on('mousemove',function(e){

                    var point = d3.mouse(this);
                    var self  = d3.select(this) ;
                    var textBox = self.select('.z-zhu-g-wrap');
                    point[0]+=30;
                    textBox.attr({
                        'transform' : 'translate(' + point[0] + ',' + point[1] + ')'
                    }) ;
                    var len = zhuStyle.length ;
                    for( var i = 0 ; i < len ; i++ ){
                        var one = zhuStyle[i] ;
                        var path = textBox.select('path.'+one.cls) ;
                        var zhu = self.select('.'+one.cls) ;
                        var text = self.select('.z'+one.cls) ;
                        var list = [] ;
                        list.push([ -5 ,( len - i ) * -30 + 10 ]) ;
                        list.push([ -15 ,( len - i ) * -30 + 10 ]) ;
                        list.push([-point[0]+parseInt(zhu.attr('x'))+5,-point[1]-parseInt(zhu.attr('height'))]) ;
                        path.attr({
                            d : line(list)
                        }) ;
                        if( one.show ){
                            path.style('display','block') ;
                            text.style('display','block') ;
                        } else {
                            path.style('display','none') ;
                            text.style('display','none') ;
                        }
                    }
                }) ;

                //@note 添加颜色说明
                var intro = outWrap.append('g').attr({
                    'class' : 'z-zhu-intro' ,
                    transform : 'translate(0,' + ( height - margin.bottom/2 ) +  ')'
                }) ;
                for( var i = 0 ; i < zhuStyle.length ; i++ ){
                    var gFlag = intro.append('g').attr({
                        'class' : 'z-zhu-intro-g',
                        transform : 'translate(' + ( margin.left + ( width / zhuStyle.length ) * i ) + ',0)'
                    }) ;

                    gFlag.append('rect').attr({
                        'width' : 20 ,
                        'height' : 10 ,
                        'class' : zhuStyle[i].cls ,
                        'x' : 0 ,
                        'y' : 0
                    }) ;
                    gFlag.append('text').attr({
                        x : 25 ,
                        y : 9
                    }).text(zhuStyle[i].zh||zhuStyle[i].name) ;
                }

                //@note 显示柱状图
                var renderZhu = function(){
                    var totalWidth = x(1) - x(0) ;
                    var idx = 0 , len = d3.sum(zhuStyle,function(d){if(d.show){return 1;}else{return 0;}}) ;
                    for( var i = 0 ; i < zhuStyle.length ; i++ ){
                        var one = zhuStyle[i] ;
                        var chart = d3.selectAll('.z-zhu-chart > .'+one.cls) ;
                        var zWidth = ( totalWidth - zhuMargin * ( len - 1 ) - zhuGap * 2 ) / len ;
                        if( one.show ){
                            chart.transition().attr({
                                width : zWidth ,
                                'x' : zhuGap + idx * ( zWidth + zhuMargin )
                            }) ;
                            idx++ ;
                        }else{
                            chart.transition().attr({
                                width : 0
                            }) ;
                        }
                    }
                } ;
                var showZhu = function(cls){
                    for(var i = 0 ; i < zhuStyle.length ; i++ ){
                        if( zhuStyle[i].cls === cls ){
                            zhuStyle[i].show = true;
                        }
                    }
                } ;
                var hideZhu = function(cls){
                    for(var i = 0 ; i < zhuStyle.length ; i++ ){
                        if( zhuStyle[i].cls === cls ){
                            zhuStyle[i].show = false;
                        }
                    }
                } ;

                d3.selectAll('.z-zhu-intro-g').on('click',function(){
                    var self = d3.select(this) ;
                    var cls = self.select('rect').attr('class') ;
                    if(!self.classed('z-zhu-intro-g-disable')){
                        self.classed('z-zhu-intro-g-disable',true) ;
                        hideZhu(cls) ;
                        renderZhu() ;
                    } else {
                        self.classed('z-zhu-intro-g-disable',false) ;
                        showZhu(cls) ;
                        renderZhu() ;
                    }
                }) ;

            }(window)) ;
        </script>
    </body>
</html>